import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { TreeRepository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { CatalogEntity } from './catalog.entity';
import { ArticleContentWithMission, CatalogWithMission } from './catalog.types';
import { DataSource } from 'typeorm';
import { ArticleContentService } from '../article/article-content/article-content.service';
import { ArticleContentEntity, ArticleContentType } from '../article/article-content/article-content.entity';
import { MissionLogService } from '../mission/mission-log/mission-log.service';
import { isNil } from 'lodash';
import { CreateCatalogDto } from './dto/create-catalog.dto';
import { CommonStatus } from '~/common/entity/common.entity';
import { UpdateCatalogDto } from './dto/update-catalog.dto';

@Injectable()
export class CatalogService {
	constructor(
		@InjectRepository(CatalogEntity)
		private catalogRepository: TreeRepository<CatalogEntity>,
		private articleContentService: ArticleContentService,
		private missionLogService: MissionLogService,
	) { }

	processCatalogTree(
		tree: CatalogWithMission[],
		contentList: ArticleContentWithMission[],
		checkVisibility: boolean = false
	): CatalogWithMission[] {
		tree.sort((a, b) => a.sortOrder - b.sortOrder);

		// 处理每个节点的子节点
		tree.forEach((node) => {
			delete node.createdAt;
			delete node.updatedAt;
			delete node.sortOrder;
			delete node.isActive;

			// 处理每个节点的内容
			const content = contentList.find((content) => content.code === node.code);

			if (content) {
				node.banner = content.banner;
				node.video = content.video;
				node.articleId = content.id;
				node.isFinish = content.isFinish; // 添加用户完成状态
			}

			// 如果需要检查可见性，为每个节点添加 isVisible 属性
			// 为每个节点添加 isVisible 属性，根据发布时间区间判断是否展示
			const now = new Date();
			const pushTime = node.pushStartTime ? new Date(`${node.pushStartTime}`) : null;
			const expireTime = node.pushEndTime ? new Date(`${node.pushEndTime}`) : null;

			// 如果没有设置发布时间，则默认可见
			if (!pushTime && !expireTime) {
				node.isVisible = false;
			} else {
				node.isVisible = (!pushTime || now >= pushTime) && (!expireTime || now <= expireTime);
			}

			if (node.children && node.children.length > 0) {
				// 递归处理子树
				node.children = this.processCatalogTree(node.children, contentList, checkVisibility);
				// 如果处理后没有子节点，则删除children属性
				if (node.children.length === 0) {
					delete node.children;
				}

				// 如果子元素中有任何一个是可见的，则父节点也应该可见
				if (!node.isVisible) {
					node.isVisible = node.children.some(child => child['isVisible'] === true);
				}
			} else if (node.children && node.children.length === 0) {
				// 如果children是空数组，则删除该属性
				delete node.children;
			}
		});

		return tree;
	}

	/**
	 * 纯净版本的目录树组装函数 - 用于cms数据查看
	 * 只处理基本的树结构，不包含过期判断和内容组装
	 * @param tree 目录树数组
	 * @returns 处理后的目录树
	 */
	processPureCatalogTree(tree: CatalogEntity[]): CatalogEntity[] {
		// 按排序字段排序
		tree.sort((a, b) => a.sortOrder - b.sortOrder);

		// 处理每个节点
		tree.forEach((node) => {
			// 清理不需要的字段
			delete node.createdAt;
			delete node.updatedAt;
			delete node.sortOrder;
			delete node.isActive;

			// 递归处理子节点
			if (node.children && node.children.length > 0) {
				node.children = this.processPureCatalogTree(node.children);
				// 如果处理后没有子节点，则删除children属性
				if (node.children.length === 0) {
					delete node.children;
				}
			} else if (node.children && node.children.length === 0) {
				// 如果children是空数组，则删除该属性
				delete node.children;
			}
		});

		return tree;
	}

	/**
	 * 查询所有目录
	 */
	async findAll(categoryId?: number, userId?: number): Promise<CatalogWithMission[]> {
		const contentList: ArticleContentEntity[] = await this.articleContentService.findByTypeAndCategoryId(ArticleContentType.MEDICAL_KNOWLEDGE, categoryId);

		const userFinishedContent = [];

		if (!isNil(userId)) {
			const contentIds = await this.missionLogService.findByCatalog(categoryId, userId);
			userFinishedContent.push(...contentIds);
		}

		const contentFinishList = contentList.map((content: ArticleContentWithMission) => {
			// 为每个内容添加用户完成状态
			content.isFinish = userFinishedContent.includes(content.id);

			return content;
		})

		// 使用 TypeORM 的树形查询，只查询激活状态的节点
		const tree = await this.catalogRepository.findTrees({
			relations: ['children'],
		});

		// 过滤出激活状态的节点
		const activeTree = categoryId ? tree.filter(node => node.categoryId === categoryId) : tree;
		const filteredTree = this.filterActiveNodes(activeTree);

		this.processCatalogTree(filteredTree, contentFinishList);

		return filteredTree;
	}

	async findByCategoryId(categoryId?: number, userId?: number): Promise<CatalogEntity[]> {
		return await this.findAll(categoryId, userId);
	}

	/**
	 * 过滤激活状态的节点（递归）
	 * @param nodes 节点数组
	 * @returns 过滤后的激活节点数组
	 */
	private filterActiveNodes(nodes: CatalogEntity[]): CatalogEntity[] {
		return nodes
			.filter(node => node.isActive === CommonStatus.YES)
			.map(node => {
				if (node.children && node.children.length > 0) {
					node.children = this.filterActiveNodes(node.children);
				}
				return node;
			});
	}

	/**
	 * 获取在推送时间范围内的叶子节点
	 * @param categoryId 可选的分类ID
	 * @returns 返回符合条件的叶子节点数组
	 */
	async findActiveLeafNodes(categoryId?: number): Promise<Array<Partial<CatalogEntity> & { articleId?: number }>> {
		// 获取文章内容列表
		const contentList: ArticleContentEntity[] = await this.articleContentService.findByTypeAndCategoryId(ArticleContentType.MEDICAL_KNOWLEDGE, categoryId);

		// 使用 TypeORM 的树形查询获取所有节点
		const tree = await this.catalogRepository.findTrees({
			relations: ['children'],
		});

		// 如果指定了分类ID，先过滤出对应分类的节点
		const categoryTree = categoryId ? tree.filter(node => node.categoryId === categoryId) : tree;
		// 过滤出激活状态的节点
		const filteredTree = this.filterActiveNodes(categoryTree);

		// 存储符合条件的叶子节点
		const activeLeafNodes: CatalogEntity[] = [];

		// 递归函数用于遍历树并收集叶子节点
		const collectActiveLeafNodes = (nodes: CatalogEntity[]) => {
			nodes.forEach((node) => {
				// 只处理激活状态的节点
				if (node.isActive !== CommonStatus.YES) {
					return;
				}

				// 检查是否是叶子节点（没有子节点或子节点为空数组）
				const isLeafNode = !node.children || node.children.length === 0;

				if (isLeafNode) {
					// 检查节点是否在有效时间范围内
					const now = new Date();
					const pushTime = node.pushStartTime ? new Date(`${node.pushStartTime}`) : null;
					const expireTime = node.pushEndTime ? new Date(`${node.pushEndTime}`) : null;

					// 如果设置了时间范围且在有效期内，则添加到结果中
					if (pushTime || expireTime) {
						const isActive = (!pushTime || now >= pushTime) && (!expireTime || now <= expireTime);
						if (isActive) {
							// 查找对应的文章内容
							const content = contentList.find((content) => content.code === node.code);
							if (content) {
								(node as any).articleId = content.id;
							}
							activeLeafNodes.push(node);
						}
					}
				} else if (node.children && node.children.length > 0) {
					// 如果不是叶子节点，继续递归处理子节点
					collectActiveLeafNodes(node.children);
				}
			});
		};

		// 开始收集叶子节点
		collectActiveLeafNodes(filteredTree);

		return activeLeafNodes;
	}

	/**
	 * 创建目录
	 * @param createCatalogDto 创建目录的数据
	 * @returns 创建的目录实体
	 */
	async create(createCatalogDto: CreateCatalogDto): Promise<CatalogEntity> {
		// 验证code是否重复（只在激活状态的记录中检查）
		if (createCatalogDto.code) {
			const existingCatalog = await this.catalogRepository.findOne({
				where: { code: createCatalogDto.code, isActive: CommonStatus.YES }
			});
			if (existingCatalog) {
				throw new BadRequestException(`目录编码已存在: ${createCatalogDto.code}`);
			}
		}

		const catalog = new CatalogEntity();

		// 设置基本属性
		catalog.name = createCatalogDto.name;
		catalog.code = createCatalogDto.code;
		catalog.description = createCatalogDto.description;
		catalog.sortOrder = createCatalogDto.sortOrder ?? 0;
		catalog.isActive = createCatalogDto.isActive ?? CommonStatus.YES;
		catalog.categoryId = createCatalogDto.categoryId;

		// 处理推送时间
		if (createCatalogDto.pushStartTime) {
			catalog.pushStartTime = new Date(createCatalogDto.pushStartTime);
		}
		if (createCatalogDto.pushEndTime) {
			catalog.pushEndTime = new Date(createCatalogDto.pushEndTime);
		}

		// 处理父级目录（只查找激活状态的父级目录）
		if (createCatalogDto.parentId) {
			const parent = await this.catalogRepository.findOne({
				where: { id: createCatalogDto.parentId, isActive: CommonStatus.YES }
			});
			if (!parent) {
				throw new NotFoundException(`父级目录不存在或已被删除，ID: ${createCatalogDto.parentId}`);
			}
			catalog.parent = parent;
		}

		// 保存目录
		return await this.catalogRepository.save(catalog);
	}

	/**
	 * 更新目录
	 * @param updateCatalogDto 更新目录的数据
	 * @returns 更新后的目录实体
	 */
	async update(updateCatalogDto: UpdateCatalogDto): Promise<CatalogEntity> {
		// 查询目录是否存在（只查询激活状态的记录）
		const catalog = await this.catalogRepository.findOne({
			where: { id: updateCatalogDto.id, isActive: CommonStatus.YES }
		});

		if (!catalog) {
			throw new NotFoundException(`目录不存在或已被删除，ID: ${updateCatalogDto.id}`);
		}

		// 验证code是否重复（排除当前记录，只在激活状态的记录中检查）
		if (updateCatalogDto.code !== undefined && updateCatalogDto.code !== catalog.code) {
			const existingCatalog = await this.catalogRepository.findOne({
				where: { code: updateCatalogDto.code, isActive: CommonStatus.YES }
			});
			if (existingCatalog && existingCatalog.id !== updateCatalogDto.id) {
				throw new BadRequestException(`目录编码已存在: ${updateCatalogDto.code}`);
			}
		}

		// 更新基本属性
		catalog.name = updateCatalogDto.name;
		if (updateCatalogDto.code !== undefined) {
			catalog.code = updateCatalogDto.code;
		}
		if (updateCatalogDto.description !== undefined) {
			catalog.description = updateCatalogDto.description;
		}

		// 处理推送时间
		if (updateCatalogDto.pushStartTime !== undefined) {
			catalog.pushStartTime = updateCatalogDto.pushStartTime ? new Date(updateCatalogDto.pushStartTime) : null;
		}
		if (updateCatalogDto.pushEndTime !== undefined) {
			catalog.pushEndTime = updateCatalogDto.pushEndTime ? new Date(updateCatalogDto.pushEndTime) : null;
		}

		// 保存更新
		return await this.catalogRepository.save(catalog);
	}

	/**
	 * 删除目录节点（软删除）
	 * 如果节点有子节点，会递归将所有子节点的激活状态设置为0
	 * @param id 要删除的节点ID
	 * @returns 删除操作的结果
	 */
	async delete(id: number): Promise<{ success: boolean; message: string; deletedCount: number }> {
		// 查询目录节点及其所有子节点（只查询激活状态的节点）
		const catalog = await this.catalogRepository.findOne({
			where: { id, isActive: CommonStatus.YES },
			relations: ['children']
		});

		if (!catalog) {
			throw new NotFoundException(`目录不存在或已被删除，ID: ${id}`);
		}

		// 获取完整的子树结构（只包含激活状态的节点）
		const descendants = await this.catalogRepository.findDescendantsTree(catalog);

		// 统计要删除的节点数量
		let deletedCount = 0;

		// 递归软删除函数
		const softDeleteNodeRecursively = async (node: CatalogEntity): Promise<void> => {
			// 如果有子节点，先递归处理子节点
			if (node.children && node.children.length > 0) {
				for (const child of node.children) {
					// 只处理激活状态的子节点
					if (child.isActive === CommonStatus.YES) {
						await softDeleteNodeRecursively(child);
					}
				}
			}

			// 软删除当前节点（设置isActive为0）
			if (node.isActive === CommonStatus.YES) {
				node.isActive = CommonStatus.NO;
				await this.catalogRepository.save(node);
				deletedCount++;
			}
		};

		try {
			// 开始递归软删除
			await softDeleteNodeRecursively(descendants);

			return {
				success: true,
				message: `成功删除目录节点及其子节点，共删除 ${deletedCount} 个节点`,
				deletedCount
			};
		} catch (error) {
			throw new BadRequestException(`删除目录节点失败: ${error.message}`);
		}
	}

	/**
	 * CMS查询目录树结构
	 * 提供给后台管理系统使用的纯净目录树查询
	 * @param categoryId 分类ID
	 * @returns 返回处理后的目录树结构
	 */
	async findTreeForCms(categoryId?: number): Promise<CatalogEntity[]> {
		// 使用 TypeORM 的树形查询获取所有节点
		const tree = await this.catalogRepository.findTrees({
			relations: ['children'],
		});

		// 如果指定了分类ID，先过滤出对应分类的节点
		const categoryTree = categoryId ? tree.filter(node => node.categoryId === categoryId) : tree;
		// 过滤出激活状态的节点
		const filteredTree = this.filterActiveNodes(categoryTree);

		// 使用纯净版本的处理函数
		return this.processPureCatalogTree(filteredTree);
	}
}
